package insight.google.game.era.core;

import insight.google.game.era.bo.GameRoom;
import insight.google.game.era.bo.GameUser;
import insight.google.game.era.bo.Message;

import insight.google.game.era.client.proxy.HostClientProxyImpl;
import insight.google.game.era.core.cache.AppCacheManager;
import insight.google.game.era.core.cache.GameCacheManager;
import insight.google.game.era.core.cache.GameCenterCacheManager;
import insight.google.game.era.core.exception.InsightException;
import insight.google.game.era.data.DataStoreManager;
import insight.google.game.era.data.GameCenter;
import insight.google.game.era.data.GameCenterDataManager;
import insight.google.game.era.data.HistoryDataManager;
import insight.google.game.era.data.Player;
import insight.google.game.era.data.Room;
import insight.google.game.era.data.RoomDataManager;
import insight.google.game.era.data.SimpleRoomDataManager;
import insight.google.game.era.data.TransactionHandler;
import insight.google.game.era.data.User;
import insight.google.game.era.data.UserDataManager;
import insight.google.game.era.data.UserHistory;
import insight.google.game.era.mgr.HistoryManger;
import insight.google.game.era.service.RoomServiceImpl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import net.sf.jsr107cache.Cache;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.ScriptProxy;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class GameCenterManager implements ChatCenterServiceProvider, IGameCenter {

	private static final Log log = LogFactory.getLog(GameCenterManager.class);

	private final String USERLIST = "userlist";
	private final String ROOMLIST = "roomlist";
	private final String MSGLIST = "msglist";

	private static GameCenterManager instance = null;
	private long instanceNumber = -1;
	
	
	private String mainPageJSComponentId = "mainframe_instance";

	
	
	private GameCenterManager() {
	
	}

	private static ChatCenter initChatCenter() {
		ChatCenter chatCenter = null;
		GameCenterDataManager gameCenterDataManager = null;
		try {
			chatCenter = new ChatCenter(null, null);
			gameCenterDataManager = new GameCenterDataManager(Util.createTranscationHandler());
			gameCenterDataManager.addToDataStore(chatCenter);
			gameCenterDataManager.commit();
			gameCenterDataManager = new GameCenterDataManager();
			chatCenter = gameCenterDataManager.findChatCenter(ChatCenter.HOST_GAMECENTER);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (gameCenterDataManager != null) {
				gameCenterDataManager.close();
			}

		}
		return chatCenter;
	}

	public static synchronized GameCenterManager getInstance() {
		GameCenterDataManager gameCenterDataManager = null;
		GameCenter gameCenter = null;
		try {
			gameCenterDataManager = new GameCenterDataManager();
			gameCenter = gameCenterDataManager.find();
			log.debug("  gamecenter from DS   ###   "+ gameCenter);
		}finally {
			if (gameCenterDataManager != null) {
				gameCenterDataManager.close();
			}
		}
		if (instance == null) {
			log.info("getting new gamecenter manager .....");
			instance = new GameCenterManager();
			// initChatCenter();
			if (gameCenter == null) {
				gameCenter = new GameCenter();
				try{
					ChatCenter chatCenter = initChatCenter();
					gameCenterDataManager = new GameCenterDataManager(Util.createTranscationHandler());
					gameCenter.setChatCenterId(chatCenter.getId());
					gameCenterDataManager.addToDataStore(gameCenter);
					gameCenterDataManager.commit();
					log.debug("  gamecenter created in  DS   ###   "+ gameCenter);
				}finally {
					if (gameCenterDataManager != null) {
						gameCenterDataManager.close();
					}
				}
				initRoom();
				
					
					// instance.chatCenterId = instance.chatCenter.getId();
				} 
			}
			log.debug("  get gamecenter from DS 3  ###   " + instance);
		return instance;
	}

	private static void initRoom() {
		Date startDate = new Date();
		log.info("Start timeis " + startDate.toString());
		SimpleRoomDataManager simpleRoomDataManager = null;
		HashMap<String, Room> roomMap = null;
		try {
			simpleRoomDataManager = new SimpleRoomDataManager(Util.createTranscationHandler());
			roomMap = simpleRoomDataManager.initAllRoom();
			simpleRoomDataManager.commit();
		} finally {
			if (simpleRoomDataManager != null) {
				simpleRoomDataManager.close();
			}
		}
		Date endDate = new Date();
		log.info("END timeis " + endDate.toString());
		log.info("-----on load times:"
				+ (endDate.getTime() - startDate.getTime()) + "ms");
	}
	
	
	public void upgradeGameCenter(){
		log.info("Updating game Center Manager ....  ...");
		GameCenterDataManager gameCenterdataManager = null;
		try{
			gameCenterdataManager = new GameCenterDataManager(
					Util.createTranscationHandler());
			GameCenter gameCenter= gameCenterdataManager.find();
			gameCenter.upgradeDataVersion();
			gameCenterdataManager.addToDataStore(gameCenter);
			gameCenterdataManager.commit();
			log.info("Game Center manager is updated  ... n current version is   "+gameCenter.getDataVersion());
			//put updated game center in cache
			log.info("Adding game Center to cache to cahce");
			GameCenterCacheManager gameCenterCache = new GameCenterCacheManager();
			gameCenterCache.addToCache(gameCenter);
			log.info("Game Center Manager is added to Cache");
			
		}catch(Exception e){
			log.info("Some error happened  --  " + e.getMessage());
		}finally{
			if(gameCenterdataManager!= null){
				gameCenterdataManager.close();
			}
		}
	}

	public String onLoad() {
		Date startDate = new Date();
		log.info("Start timeis " + startDate.toString());
		String userName = null;
		UserDataManager userDataManager = null;
		
		//get user from session
		User currUser = Util.getUserBySession();
		log.info("User from session ---   "+ currUser);
		if(currUser == null){
			
			try{
				//get user from google sessoion if looged in
				com.google.appengine.api.users.User googUser = this.getGoogleUser();
				if (googUser == null) {
					WebContext webContext = WebContextFactory.get();
					new ScriptProxy(webContext.getScriptSession()).addFunctionCall("redirectToLogin");
					return null;
				}else{
					//get user from datastore
					log.info("Saving  user in DS ..... ");
					userDataManager = new UserDataManager(Util.createTranscationHandler(),true);
					currUser = userDataManager.findByGoogleId(googUser);
					if (currUser == null) {
						currUser = new User(googUser, null);
						
						log.info("User is saved in DS    ##  "+currUser.getName());
					}
				
					this.clearOtherData(currUser);
					currUser.setLoggedIn(true);
					userDataManager.addToDataStore(currUser);
					userDataManager.commit();
					currUser.setScriptProxy(new ScriptProxy(Util.getUserScriptSession(currUser.getName())));
					userName = currUser.getName();
					
					this.upgradeGameCenter();
					log.info("Creating user history");
					HistoryManger.getInstance().creatUserHistory();
				}	
			}catch(Exception e){
				
			}finally{
				if(userDataManager != null){
					userDataManager.close();
				}
			}
			
		}else{
			this.clearOtherData(currUser);
			userName = currUser.getName();
		}
		
		
		new ScriptProxy(WebContextFactory.get().getScriptSession())
		.addFunctionCall("componentExecFunctionWithCall","mainframe_instance", "showLoginPanel", currUser);
		
		
		Date endDate = new Date();
		log.info("END timeis " + endDate.toString());
		log.info("-----on load times:"
				+ (endDate.getTime() - startDate.getTime()) + "ms");

		return userName;
	}
	
	
	private void clearOtherData(User user){
		if(user != null && user.getRoomId() != null){
//			RoomDataManager roomDataManager = new RoomDataManager();
//			GameRoom room = roomDataManager.findById(user.getRoomId());
			(new RoomServiceImpl()).quitFromRoom(false, user);
			
			
		}
		GameCacheManager gameCache = new GameCacheManager();
		if(user != null && gameCache.getFromCache(user.getEmail()) != null){
			gameCache.getCache().remove(user.getEmail());
		}
	}

	
	public void initShowMainPage(String jsComponentId) {
		this.mainPageJSComponentId = jsComponentId;
		this.broadCastUsers("");
	}
	

	private com.google.appengine.api.users.User getGoogleUser() {
		UserService userService = UserServiceFactory.getUserService();
		return userService.getCurrentUser();
	}

	public void broadCastUsers(String userName) {
		// Collection<GameUser> userList =
		// userCacheManager.getAllFromCache().values();

		UserDataManager userDataManager = new UserDataManager();
		User currUser = Util.getUserBySession();

		HashMap<String, Object> data = this.getShowMainPageData(currUser);
		if (currUser.getScriptProxy() != null) {
			log.debug("GameCenter.broadCastUsers has proxy --- "+ currUser.getName());
			HostClientProxyImpl.getInstance().showMainPage(currUser.getScriptProxy(),this.mainPageJSComponentId, data);
		}
		

	}

	public HashMap<String, Object> getShowMainPageData(User user) {
		HashMap<String, Object> data = new HashMap<String, Object>();

		SimpleRoomDataManager simpleRoomDataManager = new SimpleRoomDataManager();
		data.put(ROOMLIST, new ArrayList<Room>(simpleRoomDataManager.findAll()
				.values()));
		UserDataManager userDataManager = new UserDataManager();
		data.put(USERLIST, new ArrayList<User>(userDataManager.findAllLoggedInUser()));
		GameCenterDataManager gameCenterDataManager = new GameCenterDataManager();
		GameCenter gameCenter = gameCenterDataManager.find();
		ChatCenter  chatCenter = gameCenterDataManager.findChatCenterById(gameCenter.getChatCenterId());
		 data.put(MSGLIST, chatCenter.getAllMessages());
		return data;
	}

	

	

	

	public void join(String roomName, String jsComponentId) {
		Date startDate = new Date();
		log.info("Start timeis " + startDate.toString());

		UserDataManager userDataManager = null;
		this.mainPageJSComponentId = jsComponentId;
		User user = Util.getUserBySession();
		try {
			RoomDataManager roomDataManager = new RoomDataManager(Util
					.createTranscationHandler(), true);
			GameRoom room = roomDataManager.findByName(roomName);
			if(room.getGameState() == GameRoom.STARTED){
				user.getScriptProxy().addFunctionCall("alert","Game Already started, please refresh your screen");
				return;
			}
//			room.setJsComponentId(jsComponentId);
			GameUser gameUser = new GameUser(user.getName(), user.getEmail());
//			gameUser.setCurrentUserHistoryId(user.getCurrentUserHistoryId());
//			gameUser.setRoomName(roomName);
			room.join(gameUser);
			log.info("   new game USER ID " + gameUser.getId());
			roomDataManager.addToDataStore(room);
			// roomDataManager.addToDataStore(gameUser);
			roomDataManager.commit();

			if (gameUser.getId() == null) {
				return;
			}

			userDataManager = new UserDataManager(Util
					.createTranscationHandler());
			user = Util.getUserBySession(userDataManager
					.getTransactionHandler());

			user.setRoomName(roomName);

			user.setRoomId(room.getRoomId());
			userDataManager.addToDataStore(user);
			userDataManager.commit();

			Date step1Date = new Date();
			log.info("step1 Date timeis " + step1Date.toString());
			log.info("-----step1 Date compare:"
					+ (step1Date.getTime() - startDate.getTime()) + "ms");

			Date findDate = new Date();
			log.info("findByName timeis " + findDate.toString());
			log.info("-----findByName compare:"
					+ (findDate.getTime() - startDate.getTime()) + "ms");

			

			Date roomJoinDate = new Date();
			log.info("room join timeis " + roomJoinDate.toString());
			log.info("-----room Join Date compare:"
					+ (roomJoinDate.getTime() - startDate.getTime()) + "ms");

			SimpleRoomDataManager simpleRoomDataManager = new SimpleRoomDataManager(
					Util.createTranscationHandler());
			Room simpleRoom = simpleRoomDataManager.findByName(roomName);

			simpleRoom.syncRoomData(room);
			simpleRoomDataManager.addToDataStore(simpleRoom);
			simpleRoomDataManager.commit();

			this.upgradeGameCenter();
		

			HashMap<String, Object> dataMap = new HashMap<String, Object>();
			dataMap.put("user", gameUser);
			dataMap.put("room", room);
			roomDataManager = new RoomDataManager();
			ChatCenter  chatCenter = roomDataManager.findChatCenterById(room.getChatCenterId());
			dataMap.put(MSGLIST, chatCenter.getAllMessages());
			 
			user.getScriptProxy().addFunctionCall(
					"componentExecFunctionWithCall", jsComponentId,
					"showGameDesk", dataMap);
			
			

			this.broadCastUsers("");
			// create room history
			// HistoryManger.getInstance().createGameHistory(room);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (userDataManager != null) {
				userDataManager.close();
			}
		}

		Date endDate = new Date();
		log.info("END timeis " + endDate.toString());
		log.info("-----join times:" + (endDate.getTime() - startDate.getTime())
				+ "ms");
		// this.initGameDeck();

	}

	public GameRoom getRoomByUser() {
		TransactionHandler txHandler = Util.createTranscationHandler();
		User user = Util.getUserBySession(txHandler);
		RoomDataManager roomDataManager = new RoomDataManager(txHandler);

		GameRoom room = roomDataManager.findByName(user.getRoomName());
		log.debug("USER  ######   " + user);
		log.debug("USER  ROOOMMM   ######   " + room);
		return room;
		// GameRoom room = roomDataManager.findById(user.getRoiomId());
		// return room;
	}

	public boolean logout(String jsComponentId) {
		UserDataManager userDataManager = null;
		HistoryDataManager historydataManager = null;
		User currUser = Util.getUserBySession();
		try {
//			userDataManager = new UserDataManager(Util.createTranscationHandler());
			
			if (currUser.getRoomId() != null
					&& !currUser.getRoomName().equals("")) {
				// display message this user can not logout as he is already
				// playing
				// he need to quit from game first
				// GameUser gameUser = Util.getUserBySession();
				currUser.getScriptProxy().addFunctionCall("alert",
						"You will be also quit from the room");
				(new RoomServiceImpl()).quitRoom();
			}
			// currUser.logoutProcess();
			historydataManager = new HistoryDataManager(Util.createTranscationHandler());
			UserHistory userHistory = historydataManager.findCurrentUSerHistory(currUser.getId());
			userHistory.setLogoutTime(new Date());
			historydataManager.addToDataStore(userHistory);
			historydataManager.commit();
			HostClientProxyImpl.getInstance().userLogout(currUser.getScriptProxy(), jsComponentId, "");
			
			userDataManager = new UserDataManager(Util.createTranscationHandler());
			currUser = userDataManager.findByName(currUser.getName());
			currUser.setLoggedIn(false);
			userDataManager.addToDataStore(currUser);
			userDataManager.commit();

			this.upgradeGameCenter();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (historydataManager != null) {
				historydataManager.close();
			}
			if (userDataManager != null) {
				userDataManager.close();
			}
		}
		// this.broadCastUsers("", jsComponentId);
		return true;

	}

	@Override
	public void sendChatMessage(String message, String jsComponentId) {
	
		User currUser = Util.getUserBySession();
		GameCenterDataManager gameCenterDataManager = null;
		RoomDataManager roomDataManager =null;
		Message msg = new Message(message);
		if (currUser != null) {
			msg.setSender(currUser.getName());
		}
		if (currUser.getRoomId() == null) {
			try {

				gameCenterDataManager = new GameCenterDataManager();
				GameCenter gameCenter = gameCenterDataManager.find();
				gameCenterDataManager.close();
				gameCenterDataManager = new GameCenterDataManager(Util.createTranscationHandler());
				ChatCenter chatCenter = gameCenterDataManager.findChatCenterById(gameCenter.getChatCenterId());
				chatCenter.setJsComponentId(jsComponentId);

				chatCenter.sendMessage(msg, currUser);
				
				gameCenterDataManager.addToDataStore(chatCenter);
				gameCenterDataManager.commit();
				this.upgradeGameCenter();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (gameCenterDataManager != null) {
					gameCenterDataManager.close();
				}
			}

		} else {
			try {
				gameCenterDataManager = new GameCenterDataManager();
				
				roomDataManager = new RoomDataManager(Util.createTranscationHandler());
				GameRoom room = roomDataManager.findByName(currUser.getRoomName());
				
				ChatCenter chatCenter = gameCenterDataManager.findChatCenterById(room.getChatCenterId());
//				SimpleRoomDataManager simpleRoomDataManager = new SimpleRoomDataManager(
//						userDataManager.getTransactionHandler());
//				Room simpleRoom = simpleRoomDataManager.findByName(currUser
//						.getRoomName());
				
				chatCenter.setJsComponentId(jsComponentId);

				chatCenter.sendMessage(msg, currUser);
				
				roomDataManager.addToDataStore(chatCenter);
				room.upgradeDataVersion();
				room.publicData(currUser);
				roomDataManager.addToDataStore(room);
				roomDataManager.commit();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (roomDataManager != null) {
					roomDataManager.close();
				}
			}
		}

	}

	public void userQuitRoom(GameRoom room, User user) {
		// if(room.getGameState() == Room.GAME_OVER){
		room = new GameRoom(room.getRoomName());
		// }
		UserDataManager userDataManager = null;
		try {
			userDataManager = new UserDataManager(Util
					.createTranscationHandler());
			user = userDataManager.findByName(user.getName());
			user.setRoomName("");
			userDataManager.addToDataStore(user);
			this.upgradeGameCenter();
//			GameCenterDataManager gameCenterdataManager = new GameCenterDataManager(
//					userDataManager.getTransactionHandler());
//			gameCenterdataManager.addToDataStore(instance);
//			this.upgradeDataVersion();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (userDataManager != null) {
				userDataManager.close();
			}
		}
		this.broadCastUsers("");
	}

	@Override
	public void login() throws InsightException {

	}

	@Override
	public long getDataVersion() throws InsightException {
		return 0; 
	}

	@Override
	public boolean publicData(User user,long dataVersion) throws InsightException {
		if (user.getScriptProxy() != null) {
			HostClientProxyImpl.getInstance().publicDataVersion(
					user.getScriptProxy(), mainPageJSComponentId,
					dataVersion);
		}

		return false;
	}

	@Override
	public boolean upgradeDataVersion() throws InsightException {
		return false;
	}

	public boolean checkDataVersion(long dataVersion) {
		long serverVersion;
		// try {
		// serverVersion = this.getDataVersion();
		// if (dataVersion != serverVersion) {
		// String errorMsg = "some transfer data had lost!";
		// Collection<GameUser> userList =
		// userCacheManager.getAllFromCache().values();
		// for (GameUser user : userList) {
		// if(user.getScriptProxy() != null){
		// hostClientProxy.publicDataVersion(user.getScriptProxy(),
		// mainPageJSComponentId, this.getDataVersion());
		// }else{
		// HubServiceManager.getInstance().addPendingEvent(user,
		// mainPageJSComponentId, this.getDataVersion(), )
		// }
		// }
		// return false;
		// }
		// } catch (InsightException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		return false;
	}

	public void clearCache() {
		GameCacheManager gameCache = new GameCacheManager();
		Cache cache = gameCache.getCache();
		 
		 log.debug("Before CACHE getting cleared, cache size is " + cache.size());
		 if (cache == null) {
			  cache.clear();
			
			 }
		 log.debug("CACHE is Cleared --  now cache size is " + cache.size());

//		this.initRoom();
		// log.debug("Room Reinitialized  --  now cache size is " +
		// userCacheManager.getCache().size());
	}

	public void clearDataStore() {
		this.clearCache();
		GameCenterDataManager gameCenterDataManager = new GameCenterDataManager(
				Util.createTranscationHandler());
		gameCenterDataManager.clearDataStore();
		instance = null;
	}

	public void processVersionConflict(int version) {
		log.debug("processVersionConflict ---  user version ... " + version);
		
		GameCenterDataManager gameCenterDataManager = new GameCenterDataManager();
		GameCenter gameCenter = gameCenterDataManager.find();
		
		if (gameCenter != null && gameCenter.getDataVersion() > version) {
			log.debug("processVersionConflict ---  gamecenter version ... "+ gameCenter.getDataVersion());
			User user = Util.getUserBySession();
			if (user != null) {
				HashMap<String, Object> data = this.getShowMainPageData(user);
				HostClientProxyImpl.getInstance().showMainPage(user.getScriptProxy(),this.mainPageJSComponentId, data);
				log.debug("data updated for user  ... " + user.getName());
				try {
					this.publicData(user,gameCenter.getDataVersion());
					log.debug("version updated for user  ... "+ user.getName());
				} catch (InsightException e) {
					e.printStackTrace();
				}
			}
		}
	}

	@Override
	public boolean addUser(Player player) throws InsightException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean removePlayer(Player player) throws InsightException {
		// TODO Auto-generated method stub
		return false;
	}

	public void updateGameCenter() {
		User user = Util.getUserBySession();
		if(user.getScriptProxy() != null){
			user.getScriptProxy().addFunctionCall("componentExecFunctionWithCall","mainframe_instance","userQuitRoom");
		}
		this.broadCastUsers("");
		this.upgradeGameCenter();
	}

	@Override
	public boolean publicData(GameUser user) throws InsightException {
		// TODO Auto-generated method stub
		return false;
	}

}
